<?php

namespace OT;

class DataDictionary {
	public function __construct($table) {
		$this->headers = $table ['header'];
		$this->rows = $table ['rows'];
		$this->crossingChar = '+';
		$this->horizontalBorderChar = '-';
		$this->verticalBorderChar = '|';
		$this->borderFormat = '%s';
		$this->cellHeaderFormat = '%s';
		$this->cellRowFormat = '%s';
		$this->paddingChar = ' ';
		$this->padType = STR_PAD_RIGHT;
	}
	/**
	 * Renders table to output.
	 *
	 * Example:
	 * +---------------+-----------------------+------------------+
	 * | ISBN | Title | Author |
	 * +---------------+-----------------------+------------------+
	 * | 99921-58-10-7 | Divine Comedy | Dante Alighieri |
	 * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
	 * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
	 * +---------------+-----------------------+------------------+
	 */
	public function render($out = true) {
		if (! $this->rows)
			exit ( 'invalid table content' );
			// 获得表头行首 +---------------+-----------------------+------------------+
		$output = $this->renderRowSeparator ();
		// 获取头部输出| ISBN | Title | Author |
		$output .= $this->renderRow ( $this->headers, $this->cellHeaderFormat );
		// header存在的话再输出行分割符
		if ($this->headers) {
			$output .= $this->renderRowSeparator ();
		}
		// 渲染每一行
		foreach ( $this->rows as $row ) {
			$output .= $this->renderRow ( $row, $this->cellRowFormat );
		}
		if ($this->rows) {
			$output .= $this->renderRowSeparator ();
		}
		if ($out) {
			exit ( $output );
		} else {
			$this->cleanup ();
			return $output;
		}
	}
	public function renderWitoutHeadTail($out = true) {
		if (! $this->rows)
			exit ( 'invalid table content' );
			// 获取头部输出| ISBN | Title | Author |
		$output .= $this->renderRow ( $this->headers, $this->cellHeaderFormat );
		// header存在的话再输出行分割符
		if ($this->headers) {
			$output .= $this->renderRowSeparator ();
		}
		// 渲染每一行
		foreach ( $this->rows as $row ) {
			$output .= $this->renderRow ( $row, $this->cellRowFormat );
		}
		if ($out) {
			print ($output) ;
		} else {
			$this->cleanup ();
			return $output;
		}
	}
	
	// 渲染表格行起始分割行
	private function renderRowSeparator() {
		if (0 === $count = $this->getNumberOfColumns ()) {
			return;
		}
		
		$markup = $this->crossingChar;
		for($column = 0; $column < $count; $column ++) {
			$markup .= str_repeat ( $this->horizontalBorderChar, $this->getColumnWidth ( $column ) ) . $this->crossingChar;
		}
		
		return sprintf ( $this->borderFormat, $markup ) . PHP_EOL;
	}
	
	/**
	 * 渲染表格行.
	 *
	 * Example: | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
	 *
	 * @param array $row        	
	 * @param string $cellFormat        	
	 */
	private function renderRow(array $row, $cellFormat) {
		if (empty ( $row )) {
			return;
		}
		
		$output = $this->renderColumnSeparator ();
		for($column = 0, $count = $this->getNumberOfColumns (); $column < $count; $column ++) {
			$output .= $this->renderCell ( $row, $column, $cellFormat );
			$output .= $this->renderColumnSeparator ();
		}
		$output .= $this->writeln ( '' );
		return $output;
	}
	
	/**
	 * 带边距的渲染单元格.
	 *
	 * @param array $row        	
	 * @param integer $column        	
	 * @param string $cellFormat        	
	 */
	private function renderCell(array $row, $column, $cellFormat) {
		$cell = isset ( $row [$column] ) ? $row [$column] : '';
		return sprintf ( $cellFormat, $this->str_pad ( $this->paddingChar . $cell . $this->paddingChar, $this->getColumnWidth ( $column ), $this->paddingChar, $this->padType ) );
	}
	
	/**
	 * 渲染水平列分隔符.
	 */
	private function renderColumnSeparator() {
		return (sprintf ( $this->borderFormat, $this->verticalBorderChar ));
	}
	
	/**
	 * 获取表格的列数.
	 *
	 * @return int
	 */
	private function getNumberOfColumns() {
		if (null !== $this->numberOfColumns) {
			return $this->numberOfColumns;
		}
		
		$columns = array (
				0 
		);
		$columns [] = count ( $this->headers );
		foreach ( $this->rows as $row ) {
			$columns [] = count ( $row );
		}
		
		return $this->numberOfColumns = max ( $columns );
	}
	
	/**
	 * 获取列宽.
	 *
	 * @param integer $column        	
	 *
	 * @return int
	 */
	private function getColumnWidth($column) {
		if (isset ( $this->columnWidths [$column] )) {
			return $this->columnWidths [$column];
		}
		
		$lengths = array (
				0 
		);
		$lengths [] = $this->getCellWidth ( $this->headers, $column );
		foreach ( $this->rows as $row ) {
			$lengths [] = $this->getCellWidth ( $row, $column );
		}
		
		return $this->columnWidths [$column] = max ( $lengths ) + 2;
	}
	
	/**
	 * 获取单元格宽度.
	 *
	 * @param array $row        	
	 * @param integer $column        	
	 *
	 * @return int
	 */
	private function getCellWidth(array $row, $column) {
		if ($column < 0) {
			return 0;
		}
		
		if (isset ( $row [$column] )) {
			return $this->strlen ( $row [$column] );
		}
		
		return $this->getCellWidth ( $row, $column - 1 );
	}
	
	/**
	 * Returns the length of a string, using mb_strlen if it is available.
	 *
	 * @param string $string
	 *        	The string to check its length
	 *        	
	 * @return integer The length of the string
	 */
	protected function strlen($string) {
		// if (!function_exists('mb_strlen')) {
		return (strlen ( $string ) + mb_strlen ( $string, 'UTF8' )) / 2;
		// }
		
		// if (false === $encoding = mb_detect_encoding($string)) {
		// return strlen($string);
		// }
		
		// return mb_strlen($string, $encoding);
	}
	
	/**
	 * Called after rendering to cleanup cache data.
	 */
	private function cleanup() {
		$this->columnWidths = array ();
		$this->numberOfColumns = null;
	}
	public function writeln($line = '') {
		return $line . PHP_EOL;
	}
	public function str_pad($input, $pad_length, $pad_string, $pad_type) {
		$strlen = $this->strlen ( $input );
		if ($strlen < $pad_length) {
			$difference = $pad_length - $strlen;
			switch ($pad_type) {
				case STR_PAD_RIGHT :
					return $input . str_repeat ( $pad_string, $difference );
					break;
				case STR_PAD_LEFT :
					return str_repeat ( $pad_string, $difference ) . $input;
					break;
				default :
					$left = $difference / 2;
					$right = $difference - $left;
					return str_repeat ( $pad_string, $left ) . $input . str_repeat ( $pad_string, $right );
					break;
			}
		} else {
			return $input;
		}
	}
	
	// 生成当前数据库指定表的数据字典（字符串）
	public function generate($tableName = '') {
		$this->crossingChar = '|';
		$out_array = array ();
		$output = '';
		if ($tableName) {
			echo substr ( $tableName, strlen ( C ( 'DB_PREFIX' ) ) ) . PHP_EOL;
			$rows = array ();
			$array = M ()->query ( 'SHOW FULL COLUMNS FROM ' . $tableName );
			foreach ( $array as $key => $value ) {
				$rows [] = array (
						$value ['Field'],
						$value ['Type'],
						$value ['Comment'] 
				);
			}
			
			$this->headers = array (
					'字段',
					'类型',
					'注释' 
			);
			$this->rows = $rows;
			$this->renderWitoutHeadTail ();
		}
		echo PHP_EOL;
	}
	public function generateAll() {
		$tables = M ()->query ( 'SHOW TABLE STATUS;' );
		$tables = array_column ( $tables, 'Name' );
		foreach ( $tables as $value ) {
			$this->generate ( $value );
			$this->cleanup ();
		}
	}
}